class utils {
  constructor(cell) {
    this.cell = cell
    this.siderTool = ''
    window.drawioBus.$off('updateRequirementLabel')

    window.drawioBus.$on('updateRequirementLabel', mxUtils.bind(this, (cell) => {
      if (!Array.isArray(cell.attributeVisibleMap)) return
      this.setRequireEdge(cell)

      window.myEditor.editor.graph.cellRenderer.redrawLabel(window.myEditor.editor.graph.view.getState(cell), true)
      // window.myEditor.editor.graph.refresh()
    }))
  }
  getTextWidt(html, tag, text, fontSize) {
    let span = null
    if (html) {
      span = $(html)[0]
      span.style.fontSize = `12px`
    } else {
      span = document.createElement(tag)
      span.innerText = text
      span.style.fontSize = `${fontSize}px`
      span.style.position = 'absolute'
    }
    span.style.position = 'absolute'
    document.body.appendChild(span)
    const width = span.offsetWidth
    document.body.removeChild(span)
    return width
  }
  /**
   * @description 根据label自动设置cell宽度
   * @param cell{object} cell对象
   * @param html{String} html字符串
   * @param text{文本} html字符串
   */
  autoWidth(cell, html, text = '') {
    // const width = this.getTextWidt(html, 'div', text, 12)
    // cell.geometry.width = width < 60 ? 60 : width
  }

  setRequireEdge(cell) {
    const edges = cell.edges || []
    if (edges.some(i => i.source === null || i.target === null)) return
    // 获取最新的关系
    const attributeVisibleMap = edges.map((edge) => {
      let direction = ''
      let targetCell = {}
      if (edge.source.id === cell.id) {
        targetCell = edge.target
        direction = 'to'
      } else {
        targetCell = edge.source
        direction = 'from'
      }
      if (edge.getAttribute('tooltip') === 'Derive') {
        direction = direction === 'to' ? 'from' : 'to'
      }
      const dom = `<div style="width: 100%;height:40px;line-height: 10px;"><div style="margin: 0px ; text-align: center"> ${direction}-${ edge.getAttribute('tooltip')}
        <br><b style=""> &lt;&lt;${targetCell.getAttribute('name')}&gt;&gt; ${targetCell.getAttribute('name')}</b></div></div><hr style="width:100%;margin: 0px;" />`
      return {
        group: edge.getAttribute('tooltip'),
        visible: false,
        edgeId: edge.id,
        dom
      }
    })
    // 找到edgeId相同，即都存在的关系线
    const edgeIds = []
    cell.attributeVisibleMap.forEach(item => {
      if (!item.edgeId) item.visible = true
      const row = attributeVisibleMap.find(i => item.edgeId === i.edgeId)
      if (row) {
        // 都存在，则用新的关系数据  覆盖旧的数据
        item.dom = row.dom
        item.visible = row.visible
        edgeIds.push(row.edgeId)
      }
    })
    // 过滤掉删除的关系
    cell.attributeVisibleMap = cell.attributeVisibleMap.filter(item => !edgeIds.includes(item.edgeId))
    // 合并关系
    cell.attributeVisibleMap = cell.attributeVisibleMap.concat(attributeVisibleMap)
    //生成label
    const content = cell.attributeVisibleMap.reduce((prv, item) => {
      prv += item.visible ? item.dom : ''
      return prv
    }, '')

    const label = this.getHeader(cell, cell.value.getAttribute('name'), cell.value.getAttribute('display')) + content
    cell.value.setAttribute('label', this.getOutDiv(cell.id, label));
  }

  // ---------- 组件label相关 ----------
  /**
   * @function 生成元素的外层html
   * @param id <String> cell的id
   * @param content <String> 内容HTML
   * @returns {String} 完整的html
   */
  getOutDiv(id, content) {
    return `<div class="data-${id}" style="box-sizing: border-box;display: inline-block;font-weight: normal; font-family: Helvetica; pointer-events: all; width: 100%; height: 100%;; line-height: 100%;box-sizing: border-box;">${content}</div>`;
  }
  /**
   * @function 生成元素的头部html
   * @param cell {Object} 元素cell
   * @param name <String> name
   * @param display <String> display
   * @param attributeList <Array> 属性的list
   * @returns {String} 头部html
   */
  getHeader(cell, name, display, attributeList = []) {
    let type = cell.value.getAttribute('tooltip')
    // label不换行样式
    var ellipsisStyle = 'white-space: nowrap; overflow: hidden; text-overflow: ellipsis;';
    if (cell.value instanceof Object && (display === 'SYSML_BLOCKDEFINITION_KUAIJIEDIAN' || 'SYSML_REQUIREMENT_XQJD')) {
      type = 'block'
      const row = (window.blockType || []).find(i => i.label === cell.value.getAttribute('tooltip'))
      if (row) {
        type = row.code
      }
    }
    if (cell.value instanceof Object && display === 'SYSML_BLOCKDEFINITION_YUESUKUAIJIEDIAN') {
      type = 'constraint'
    }

    if (cell.value.getAttribute('sysmlTitle')) {
      type = cell.value.getAttribute('sysmlTitle')
    }
    if (display === 'LABEL_RECTANGLE') {
      return `<div style="box-sizing: border-box;width: 100%;height:40px;padding-top: 6px;"><div style="margin: 0px ; text-align: center; ${ellipsisStyle}"><b style="font-weight: 400">${name}</b></div></div><hr style="width:100%;margin: 0px;" />`
    }
    if (display === 'SYSML_BLOCKDEFINITION_BUJIAN') {
      return `<div style="margin: 0px ;height:40px;line-height: 40px; text-align: center;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;">${name}</div>`
    }
    if (display === 'SYSML_STATEMACHINE_ZHUANGTAI') {
      return `<div style="box-sizing: border-box;width: 100%;height:40px"><div style="line-height: 40px;margin: 0px ; text-align: center; ${ellipsisStyle}"><b style="font-weight: 700">${name}</b></div></div><hr style="width:100%;margin: 0px;" />`
    }
    return `<div style="box-sizing: border-box;width: 100%;height:40px;padding-top: 6px;"><div style="margin: 0px ; text-align: center; ${ellipsisStyle}"><b>&lt;&lt;${type}&gt;&gt;</b><br><b style="font-weight: 700;">${name}</b></div></div><hr style="width:100%;margin: 0px;" />`
  }
  /**
   * @function 获取元素内容/label
   * @param formList {Array} 新数据
   * @param oldList <Array> 旧数据
   * @param defaultShowGroup <Array> 默认显示的组名称
   * @returns {Array} 处理好的数据
   */
  getContentByArray(formList, oldList = [], defaultShowGroup = []) {
    const groups = formList.reduce((prv, item) => {
      if (!prv.some(i => i === item.group)) {
        prv.push(item.group)
      }
      return prv
    }, [])
    return groups.map((group) => {
      const formGroupList = formList.filter(i => i.group === group)
      const content = formGroupList.reduce((formPrv, form) => {
        if (form.attrLable === '名称') return formPrv
        formPrv += `<div style="box-sizing: border-box;margin: 0px;padding: 0 8%;line-height: 18px; text-align: left;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;">${form.attrLable}${form.attrLable === 'ID' ? ' = ' : '：'}${form.attrValueObject}</div>`
        return formPrv
      }, '')
      const dom = `<div class='group group-${group}' style="box-sizing: border-box;"><div style="box-sizing: border-box;font-size: 5px ; margin: 0px ; text-align: center"><i style=''>${group}</i></div>${content}<hr style="width:100%;margin: 0px;" /></div>`
      return {
        group,
        formGroupList,
        visible: defaultShowGroup.includes(group) || oldList.some(i => (i.group === group && i.visible === true)),
        dom
      }
    })
  }

  async getBlockAttributeVisibleMap(cell, cellParams) {
    const params = {
      modelId: cellParams.modelId,
      eObjectId: cellParams.eObjectId,
      objectId: cellParams.objectId,
      name: cellParams.name,
    };
    const attributeList = []

    const {
      data
    } = await window.parent.$axios.get(window.parent.g.ApiUrl2 + '/object/objectAttribute', {
      params: params
    })
    for (const key in data) {
      if (data.hasOwnProperty(key)) {
        const values = data[key];
        if (Array.isArray(values)) {
          if (key === '属性') {
            attributeList.unshift({
              group: key,
              formGroupList: [],
              visible: true, // defaultShowGroup.includes(group) || oldList.some(i => (i.group === group && i.visible === true))
              dom: `<div><div style="text-align: center; height: 30px; line-height: 30px; box-sizing: border-box;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;">${key}</div>${values.map(value=> (`<div style="text-align: left;height: 25px; line-height: 25px; box-sizing: border-box; padding: 0 10px;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;">${value.attrValueObject}</div>`)).join('')}</div><hr style="width:100%;margin: 0px;" />`,
              domHeight: 30 + values.length * 20 + 2,
            })
          } else {
            attributeList.push({
              group: key,
              formGroupList: [],
              visible: (cell.attributeVisibleMap || []).some(i => (i.group === key && Boolean(i.visible) === true)), // defaultShowGroup.includes(group) || oldList.some(i => (i.group === group && i.visible === true))
              dom: `<div><div style="text-align: center; height: 30px; line-height: 30px; box-sizing: border-box;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;">${key}</div>${values.map(value=> (`<div style="text-align: left;height: 20px; line-height: 20px; box-sizing: border-box;padding: 0 10px;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;">${(value.attrValueObject || '') || value.name}</div>`)).join('')}</div><hr style="width:100%;margin: 0px;" />`,
              domHeight: 30 + values.length * 20 + 2,
            })
          }
        }
      }
    }
    if(attributeList.length) cell.attributeVisibleMap = attributeList
  }
  /**
   * @function 设置块相关的属性
   * @param cellParams {Object} cell参数
   */
  async setBlockModuleInfo(cell, cellParams) {
    if (cell.attributeVisibleMap && cell.attributeVisibleMap.some(i => i.visible)) {
      await this.getBlockAttributeVisibleMap(cell, cellParams)
    }

    cell.attributeVisibleMap = cell.attributeVisibleMap || []
    const content = cell.attributeVisibleMap.reduce((prv, item) => {
      prv += item.visible ? item.dom : ''
      return prv
    }, '')

    const label = this.getHeader(cell, cell.value.getAttribute('name'), cell.value.getAttribute('display'), []) + content
    cell.value.setAttribute('label', this.getOutDiv(cell.id, label));

    const graph = window.myEditor.editor.graph;
    if (cell.attributeVisibleMap && graph.getCellStyle(cell)['shape'] !== 'image') {
        this.updateBlockModuleHeight(cell);
    }
  }

  updateBlockModuleHeight(cell) {
    const graph = window.myEditor.editor.graph;
    let height =  this.getAttributeVisibleMapHeight(cell);
    graph.getModel().beginUpdate();
    try {
      let geometry = graph.getModel().getGeometry(cell).clone();
      if (geometry.height >= height) {
        height = geometry.height
      }
      const rectangle = new mxRectangle(geometry.x, geometry.y, geometry.width, height)
      graph.resizeCells([cell], [rectangle]); // 设置尺寸
      graph.view.revalidate();
    } finally {
      // endUpdate传递false,当前这条操作不记录到记录堆栈
      graph.getModel().endUpdate(false);
    }
  }

  /**
   * @function 清除某条记录
   */
  ignoreOperationHistory() {
    const myEditor = window.myEditor;
    if (myEditor.editor.undoManager.history.length) {
      myEditor.editor.undoManager.history.pop();
      myEditor.editor.undoManager.indexOfNextAdd = myEditor.editor.undoManager.history.length;
    }
  }

  /**
   * @function 设置流规范相关的属性
   * @param cellParams {Object} cell参数
   */
  async setFlowNormModuleInfo(cell, cellParams) {
    cell.value.setAttribute('label', cell.value.getAttribute('name'));
  }
  /**
   * @function 获取需求内容/label
   * @param formList {Array} 新数据
   * @param oldList <Array> 旧数据
   * @param show <Array> 默认显示隐藏
   * @returns {Array} 处理好的数据
   */
  getRequirementContent(formList, oldList = [], show = false) {
    const groups = formList.reduce((prv, item) => {
      if (!prv.some(i => i === item.group)) {
        prv.push(item.group)
      }
      return prv
    }, [])
    return groups.map((group) => {
      const formGroupList = formList.filter(i => i.group === group)
      const content = formGroupList.reduce((formPrv, form) => {
        if (form.attrLable === '名称') return formPrv
        formPrv += `<div style="box-sizing: border-box;margin: 0px;padding: 0 8%;line-height: 18px; text-align: left;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;">${form.attrLable}：${form.attrValueObject}</div>`
        return formPrv
      }, '')
      const dom = `<div class='group group-${group}' style="box-sizing: border-box;"><div style="box-sizing: border-box;font-size: 5px ; margin: 0px ; text-align: center"><i style=''>${group}</i></div>${content}<hr style="width:100%;margin: 0px;" /></div>`
      return {
        group,
        formGroupList,
        visible: oldList.some(i => show || (i.group === group && i.visible === true)),
        dom
      }
    })
  }

  /**
   * @function 获取元素属性
   * @param cellParams {Object} 参数
   * @param objectInfoPerParams {Object} 额外参数
   */
  async getObjectInfo(cellParams, objectInfoPerParams = {}) {
    const params = {
      modelId: cellParams.modelId,
      eObjectId: cellParams.eObjectId,
      objectId: cellParams.objectId,
      name: cellParams.name,
      pageObjNum: cellParams.pageObjNum,
      xuqiuId: cellParams.xuqiuId,
      identityCode: cellParams.identityCode,
      ...objectInfoPerParams
    };
    if (!window.parent.MODELID) {
      return false
    }
    const res = await window.parent.$axios.get(window.parent.g.ApiUrl2 + '/object/editGraphObject', {
      params: params
    })
    const attributeList = [];
    // 根据类型分组
    res.data.attributeTab.forEach(item => {
      if (Array.isArray(item.objectFormList) && item.objectFormList.length) {
        item.objectFormList.forEach(objectForm => {
          let value = ''
          // 根据类型获取 attrValueObject
          if (['readonly_object', 'enum'].indexOf(objectForm.formType) > -1) {
            const row = (objectForm.list || []).find(i => i.id === objectForm.attrValueObject)
            value = row ? row.name : objectForm.attrValueObject
          } else if (objectForm.formType === 'combobox') {
            const row = (objectForm.list || []).find(i => i.code === objectForm.attrValueObject)
            value = row ? row.name : objectForm.attrValueObject
          } else if (objectForm.formType === 'select') {
            value = (objectForm.list || []).map(i => i.name).join(',') || ''
          } else {
            value = objectForm.attrValueObject
          }
          attributeList.push({
            attrLable: objectForm.attrLable,
            attrValueObject: value,
            group: item.title
          });
        });
      } else if (item.type === 'object') {
        attributeList.push({
          attrLable: item.title,
          attrValueObject: (item.objectAttributeForm.list || []).map(i => i.name).toString(),
          group: item.title
        });
      }
    });
    return attributeList
  }
  /**
   * @function 获取值属性的高度
   * @param cell {Object} 对应元素
   */
  getAttributeVisibleMapHeight(cell) {
    let height = 40;
    cell.attributeVisibleMap.forEach(item => {
      if (item.visible) {
        height += item.domHeight
      }
    })

    return height
  }
  /**
   * @function 更新元素的属性显示隐藏
   * @param cell {Object} 对应元素
   */
  async upDataCellLableVisible(cell) {
    // 设置快图的内容
    if (cell.value.getAttribute('display') === 'SYSML_BLOCKDEFINITION_KUAIJIEDIAN') {
      await this.setBlockModuleInfo(cell, resolveCell(cell))
    }

    var valueObj = cell.getValue();
    const attributeVisibleMap = cell.attributeVisibleMap
    let attributeList = []
    // 非需求
    if (cell.value.getAttribute('display') !== 'SYSML_REQUIREMENT_XQJD') {
      attributeList = attributeVisibleMap.map(i => i.formGroupList).reduce((prv, item) => {
        prv = [...prv, ...item]
        return prv
      }, [])
    }
    const content = cell.attributeVisibleMap.reduce((prv, item) => {
      prv += item.visible ? item.dom : ''
      return prv
    }, '')

    const label = this.getHeader(cell, cell.value.getAttribute('name'), cell.value.getAttribute('display'), attributeList) + content
    valueObj.setAttribute('label', this.getOutDiv(cell.id, label));

    const graph = window.myEditor.editor.graph;
    if (cell.attributeVisibleMap && graph.getCellStyle(cell)['shape'] !== 'image') {
      this.updateBlockModuleHeight(cell);
    }

    // 重新选择,触发 mxVertexToolHandler.init
    // var cells = window.myEditor.editor.graph.getSelectionCells()
    // window.myEditor.editor.graph.clearSelection()
    // window.myEditor.editor.graph.setSelectionCells(cells)
  }

  /**
   * @function 设置端口的提供接口和所需接口
   * @param cell {Object} 传入的cell对象
   */
  async setPortProvideAndRequired(cell, cellParams) {
    const attributeList = await this.getObjectInfo(cellParams)
    /**
     * @function 设置端口接口
     * @param attr {Object} cell的属性
     * @param type {String} 是提供还是所需
     * @param style {String} edge的样式
     */
    function setPortEdge(attr, type, style) {
      const edgeCell = new mxCell(
          attr.attrValueObject,
          new mxGeometry(-1, 0, 0, 0),
          style
      );

      const cellWidth = cell.geometry.width;
      edgeCell.requireInterface = type
      edgeCell.edge = true
      edgeCell.geometry.relative = false;
      edgeCell.geometry.offset = new mxPoint(0, 0);
      edgeCell.geometry.sourcePoint = new mxPoint(cellWidth / 2, cellWidth / 2);
      const lineLength = 80

      if (cell.position === 'left') {
        edgeCell.geometry.targetPoint = new mxPoint(-lineLength, cellWidth / 2);
      } else if (cell.position === 'top') {
        edgeCell.geometry.targetPoint = new mxPoint(cellWidth / 2, -lineLength);
      } else if (cell.position === 'right') {
        edgeCell.geometry.targetPoint = new mxPoint(lineLength, cellWidth / 2);
      } else if (cell.position === 'bottom') {
        edgeCell.geometry.targetPoint = new mxPoint(cellWidth / 2, lineLength);
      }
      edgeCell.geometry.offset.x = edgeCell.geometry.targetPoint.x / 2
      edgeCell.geometry.offset.y = edgeCell.geometry.targetPoint.y / 2

      cell.insert(edgeCell)

      window.myEditor.editor.graph.overHandler.adjustEndPoint(edgeCell)
    }

    const edges = cell.children || []
    attributeList.forEach(attr => {
      if (attr.attrLable === "请求接口") {
        const provideEdge = edges.find(edge => edge.requireInterface === 'provide')
        if (attr.attrValueObject && provideEdge) {
          provideEdge.value = attr.attrValueObject
        }
        if (!attr.attrValueObject && provideEdge) {
          window.myEditor.editor.graph.removeCells([provideEdge]);
        }
        if (!provideEdge && attr.attrValueObject) {
          setPortEdge(attr, 'provide', 'edgeStyle=none;html=1;align=center;verticalAlign=top;endArrow=sysMLProvInt;endSize=12;')
        }
      }
      if (attr.attrLable === '所需接口') {
        const requireEdge = edges.find(edge => edge.requireInterface === 'require')
        if (attr.attrValueObject && requireEdge) {
          requireEdge.value = attr.attrValueObject
        }
        if (!attr.attrValueObject && requireEdge) {
          window.myEditor.editor.graph.removeCells([requireEdge]);
        }
        if (!requireEdge && attr.attrValueObject) {
          setPortEdge(attr, 'require', 'edgeStyle=none;html=1;align=center;verticalAlign=bottom;endArrow=sysMLReqInt;endSize=8;')
        }
      }
    })
    window.myEditor.editor.graph.refresh()
  }

  /**
   * @function 设置流端口方向
   * @param cell {Object} 传入的cell对象
   */
  async setDailtPortDirection(cell, cellParams) {
    // 上下左右箭头 + 上下、左右箭头
    const attributeList = await this.getObjectInfo(cellParams);
    const type = attributeList.find(i => i.attrLable === '类型')
    cell.value.setAttribute('label', `${cell.value.getAttribute('name')}：${type.attrValueObject}`);
    window.myEditor.editor.graph.refresh()
    const row = attributeList.find(i => i.attrLable === '方向')
    cell.direction = row.attrValueObject
    myEditor.editor.graph.setDailtPortDirection(cell)
  }
  setRelationMultiplicity(cell) {
    function createMultiplicityCell(cell, name, key, style, x) {
      const multiplicityCell = new mxCell(
        name,
        new mxGeometry(-1, 0, 0, 0),
        style
      );
      multiplicityCell[`multiplicityId`] = `multiplicityId-${cell.id}`
      multiplicityCell.connectable = false
      multiplicityCell.vertex = true
      multiplicityCell.geometry.x = x;
      multiplicityCell.geometry.relative = true;
      key === 'target' ? multiplicityCell.islineTarget = true : multiplicityCell.islineTarget = false;
      key === 'source' ? multiplicityCell.islineSource = true : multiplicityCell.islineSource = false;
      window.myEditor.editor.graph.addCells([multiplicityCell], cell)
    }
    const delStack = [];
    (cell.children || []).forEach(c => {
      if (c.multiplicityId) {
        delStack.push(() => window.myEditor.editor.graph.removeCells([c]))
      }
    })
    // 更新
    delStack.forEach(stack => stack())

    if (cell.value.getAttribute('display') === 'SYSML_BLOCKDEFINITION_YINYONGGUANLIANPATH' || cell.value.getAttribute('display') === 'SYSML_BLOCKDEFINITION_FUHEGUANLAIPATH') {
      if (cell.hasOwnProperty('lineTargetShowName') && cell.target) {
        createMultiplicityCell(cell, cell.lineTargetShowName, 'target', 'resizable=0;html=1;align=right;verticalAlign=bottom;labelBackgroundColor=none;fontSize=10', 1)
        createMultiplicityCell(cell, cell.target.value.getAttribute('name'), 'target', 'resizable=0;html=1;align=right;verticalAlign=top;labelBackgroundColor=none;fontSize=10', 1, )
      }
      if (cell.hasOwnProperty('lineSourceShowName') && cell.source) {
        createMultiplicityCell(cell, cell.lineSourceShowName, 'source', 'resizable=0;html=1;align=left;verticalAlign=bottom;labelBackgroundColor=none;fontSize=10', -1)
        createMultiplicityCell(cell, cell.source.value.getAttribute('name'), 'source', 'resizable=0;html=1;align=left;verticalAlign=top;labelBackgroundColor=none;fontSize=10', -1, )
      }
    } else {
      //多重性
      createMultiplicityCell(cell, cell.lineSourceShowName, 'source', 'resizable=0;html=1;align=right;verticalAlign=top;labelBackgroundColor=none;fontSize=10', -1)
      createMultiplicityCell(cell, cell.lineTargetShowName, 'target', 'resizable=0;html=1;align=left;verticalAlign=top;labelBackgroundColor=none;fontSize=10', 1)
    }
    window.myEditor.editor.graph.refresh()
  }
  updateAllCellLabel() {
    const stackList = []
    Object.keys(myEditor.editor.graph.model.cells).forEach(key => {
      const cell = myEditor.editor.graph.model.cells[key]
      if (cell.value instanceof Object) {
        const label = cell.value.getAttribute('label')
        const displayIgnore = ['SYSML_BLOCKDEFINITION_BUJIAN', 'LABEL_ER_ATTRIBUTE'] // 'SYSML_REQUIREMENT_XQJD'
        if (label.indexOf('showLabel="show"') < 0 && !displayIgnore.includes(cell.value.getAttribute('display'))) {
          stackList.push(() => this.putLabel(cell, cell.value.getAttribute('name'), resolveCell(cell)))
        }
      }
    })
    myEditor.editor.graph.getModel().beginUpdate();
    try {
      stackList.forEach(stack => stack())
    } finally {
      myEditor.editor.graph.getModel().endUpdate();

    }
  }

  async setActiveDYDZ_BT(cell, cellParams) {
    const attributeList = await this.getObjectInfo(cellParams)
    const hasBT = attributeList.some(i => i.attrLable === '引用的活动' && i.attrValueObject)
    const overlays = myEditor.editor.graph.getCellOverlays(cell)
    let overlay;
    if (hasBT) {
      overlay = new mxCellOverlay(
        new mxImage('./img/sysml/db.png', 16, 16),
        null,
        mxConstants.ALIGN_RIGHT,
        mxConstants.ALIGN_MIDDLE,
        new mxPoint(-18, 0)
      );
      myEditor.editor.graph.addCellOverlay(cell, overlay);
    }
    if (!hasBT && overlays) {
      myEditor.editor.graph.removeCellOverlays(cell);
    }

  }

  async setDown_T_Label(cell, cellParams) {
    const attributeList = await this.getObjectInfo(cellParams)
    const labelRow = attributeList.find(i => i.attrLable === '标识' && i.attrValueObject)
    cell.value.setAttribute('label', labelRow.attrValueObject)
    window.myEditor.editor.graph.refresh()
  }


  /**
   * @description 设置图片模式时，设置label及位置
   * @param {mxCell} cell 目标cell
   * @param {string} label 目标label
   */
  setImgShapeLabel(cell, label) {
    if (cell.style.includes('image=img/clipart/main.png;') || cell.style.includes('image=img/clipart/deputy.png;')) {
      // 逻辑属性操作
      this.setLabelErAttributeInfo(cell, label)
      return
    }
    const graph = myEditor.editor.graph
    // 使用了编辑图片时  设置label在下方
    cell.value.setAttribute('label', label)
    cell.value.setAttribute('name', label)
    const state = graph.view.getState(cell)
    let style = graph.getCellStyle(cell)
    style.align = 'center'
    style.verticalLabelPosition = 'bottom'
    /**
     * @description 解决高级作战概念图图片节点，label在节点下方时，label的高度为100%，导致包含关系的大小异常
     * @link http://192.168.0.100:8000/zentao/bug-view-21756.html
     */
    delete style.html
    delete style.whiteSpace
    let styleStr = ''
    for (const key in style) {
      if (style.hasOwnProperty(key)) {
        styleStr += `${key}=${this.formatImageDataUrl(style[key])};`
      }
    }
    cell.style = styleStr
  }

  setLabelErAttributeInfo(cell, name) {
    cell.setLabelErAttributeInfoHaveChange = 'true';
    let havaFkOrPkName = this.havaFkOrPk(cell, name);
    cell.setAttribute('tooltip', name);
    cell.setAttribute('name', name);
    cell.setAttribute('label', havaFkOrPkName.name);
    if (havaFkOrPkName.flag) {
      myEditor.editor.graph.setLabelErAttributeInfo(cell, havaFkOrPkName.name);
    }
  }

  havaFkOrPk(cell, name) {
    if (cell.getValue().getAttribute('label')) {
      let label = ['PK', 'FK'].find(item => {
        return cell.getValue().getAttribute('label').includes(item)
      })
      if (label) {
        return {
          flag: true,
          name: name + ` (${label})`
        }
      }
      return {
        flag: false,
        name: name
      }
    }
    return {
      flag: false,
      name: name
    }
  }

  /**
   * @description 四化五层图，层label的特殊处理
   * @param {mxCell} cell 目标cell
   * @param {string} label 目标label
   */
  setHexagonalRectLabel(cell) {
    if (cell.children.length) {
      const rect = cell.children[0]
      rect.value = cell.value.getAttribute('name')
      cell.value.setAttribute('label', '')
    }
  }

  /**
   * @function 根据display 设置元素的label、name
   * @param cell {Object} 传入的cell对象
   * @param name {String} cell对象的name属性
   * @param cellParams {Object} cell对象的解析属性
   * @param label {string=}
   */
  async putLabel(cell, name, cellParams, label) {
    const graph = myEditor.editor.graph
    if (!cellParams.modelId) return

    try {
      // 使用了编辑图片时的额外操作
      if (graph.getModel().isVertex(cell) && cell.style?.includes('shape=image')) {
        this.setImgShapeLabel(cell, name)
        return
      }

      var valueObj = cell.getValue();
      const display = cell.value.getAttribute('display')
      valueObj.setAttribute('name', name);

      // 设置块图的内容
      if (display === 'SYSML_BLOCKDEFINITION_KUAIJIEDIAN') {
        this.setBlockModuleInfo(cell, cellParams)
        return
      }
      //设置流规范的内容流规范
      if (valueObj.getAttribute('tooltip') === '流规范') {
        this.setFlowNormModuleInfo(cell, cellParams)
        return
      }
      //约束块 SYSML_BLOCKDEFINITION_YUESUKUAIJIEDIAN
      if (display === 'SYSML_BLOCKDEFINITION_YUESUKUAIJIEDIAN') {
        this.setBlockModuleInfo(cell, cellParams)
        return
      }

      // 设置端口的提供接口和所需接口
      if ([...window.portList, 'SYSML_PARAMETRIC_YUESHUCANSHUJIEDIAN'].includes(display)) {
        this.setPortProvideAndRequired(cell, cellParams)
      }

      //设置流端口的方向
      if (display === 'SYSML_BLOCKDEFINITION_DAILIPORTJIEDIAN' || display === 'SYSML_INTERNALMODULE_DAILIPORTJIEDIAN') {
        this.setDailtPortDirection(cell, cellParams)
        return
      }

      // 部件和引用属性
      if (cell.objectLabel) {
        if (cell.style.includes('swimlane')) {
          valueObj.setAttribute('label', cell.objectLabel);
          return
        }
        const label = `<div style="margin: 0px ;height:40px;line-height: 40px; text-align: center;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;" showLabel="show">${cell.objectLabel}</div>`
        valueObj.setAttribute('label', label);

        // 时序图引用部件时，存在objectLabel就删除。编辑时会按逻辑重新赋值，删除不影响。
        if (window.displayTypeComboStr.includes(display) && valueObj.nodeName === 'quote' && cell.objectLabel) {
          delete cell.objectLabel
        }
        return
      }

      // 添加书名号
      if (cell.value.nodeName === 'relation') {
        if (cell.value.getAttribute('sysmlTitle')) {
          cell.value.setAttribute('label', `&lt;&lt;${cell.value.getAttribute('sysmlTitle')}&gt;&gt;`);
        } else {
          // 时序图连线的label
          if (SEQUENCE_RELATION_DISPLAY.indexOf(display) > -1) {
            // 207调整需求线展示label
            cell.value.setAttribute('label', name.length > 15 ? name.substring(0, 15) + '...' : name);
            console.log(cell)
          } else {
            cell.value.setAttribute('label', '');
          }
        }
        //模块定义图的Association特殊处理，显示name
        if (display === 'SYSML_BLOCKDEFINITION_YINYONGGUANLIANPATH' && cell.value.getAttribute('tooltip') === 'Association') {
          cell.value.setAttribute('label', name);
        }

        // 设置关系线的多重性
        if (cell.lineTargetShowName || cell.lineSourceShowName) {
          if (cell.value.getAttribute('sysmlTitle')) {
            cell.value.setAttribute('label', `&lt;&lt;${cell.value.getAttribute('sysmlTitle')}&gt;&gt;`);
          } else {
            cell.value.setAttribute('label', '');
          }
          if (display === 'SYSML_BLOCKDEFINITION_YINYONGGUANLIANPATH' && cell.value.getAttribute('tooltip') === 'Association') {
            cell.value.setAttribute('label', name);
          }
          this.setRelationMultiplicity(cell)
        }

        if (this.isEmptyValue(cell.lineSourceShowName) || this.isEmptyValue(cell.lineTargetShowName)) {
          var removeCells = cell.children && cell.children.filter(mxUtils.bind(this, function (c) {
            return this.isEmptyValue(cell.lineSourceShowName) && c.islineSource || this.isEmptyValue(cell.lineTargetShowName) && c.islineTarget
          }))
          removeCells && removeCells.length && graph.removeCells(removeCells)
        }

        if (window.DrawioStore.modelType === 'DIAGRAM_IDEF0') {
          cell.value.setAttribute('label', name);
        }

        return
      }

      // 设置活动图-调用动作行为的钯图
      if (display === 'SYSML_ACTIVITY_DIAOYONGDONGZUOJIEDIAN') {
        valueObj.setAttribute('label', name);
        this.setActiveDYDZ_BT(cell, cellParams)
        return;
      }

      // 设置活动图等待时间
      if (display === 'LABEL_DENGDAISHIJIANDONGZUO') {
        const attributeList = await this.getObjectInfo(cellParams)
        const timer = attributeList.find(i => i.attrLable === '持续时间')
        valueObj.setAttribute('label', timer.attrValueObject ? `${timer.attrValueObject}毫秒` : '');
        return;
      }

      // 活动图设置关系的守护
      if (['SYSML_ACTIVITY_KONGZHILIULUJING', 'SYSML_ACTIVITY_DUIXIANGLIUJIEDIAN'].includes(display)) {
        const attributeList = await this.getObjectInfo(cellParams)
        const attrObject = attributeList.find(i => i.attrLable === '守护')
        valueObj.setAttribute('label', attrObject.attrValueObject ? `[${attrObject.attrValueObject}]` : '');
        return;
      }
      // 值类型
      if ((display === 'LABEL_RECTANGLE' || display === 'SYSML_BLOCKDEFINITION_BUJIAN')) {
        let label = null
        if (cell.value.getAttribute('sysmlTitle')) {
          label = `<div style="box-sizing: border-box;width: 100%;height:40px;padding-top: 6px;margin: 0px ; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;"><b>&lt;&lt;${cell.value.getAttribute('sysmlTitle')}&gt;&gt;</b><br/><b style="font-weight: 700">${name}</b></div>`
        } else {
          label = `<div style="box-sizing: border-box;width: 100%;height:40px;margin: 0px ; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;"><br/><b style="font-weight: 700">${name}</b></div>`
        }
        // if (!label) return
        // this.autoWidth(cell, label)
        // this.updateCellSize(cell);

        valueObj.setAttribute('label', label);
        return
      }

      // 设置信息活动的输入输入，倒T元素的label
      if (display === 'LABEL_DOWN_T') {
        this.setDown_T_Label(cell, cellParams)
      }

      // 四化五层图，层label的特殊处理
      if (display === 'LABEL_HEXAGONAL_RECT_LANE') {
        this.setHexagonalRectLabel(cell)
      }

      const displayList = ['SYSML_BLOCKDEFINITION_YUESUKUAIJIEDIAN', 'UML_COMPONENT_INTERFACE']
      if (displayList.some(i => i === display)) {
        // 获取数据渲染label
        cellParams.name = name || cellParams.name
        const attributeList = await this.getObjectInfo(cellParams)
        const content = this.getContentByArray(attributeList, cell.attributeVisibleMap || [], ['属性']).reduce((prv, item) => {
          prv += item.visible ? item.dom : ''
          return prv
        }, '')
        cell.attributeVisibleMap = this.getContentByArray(attributeList, cell.attributeVisibleMap || [], ['属性'])
        const label = this.getHeader(cell, name, display, attributeList) + content
        valueObj.setAttribute('label', this.getOutDiv(cell.id, label));
      } else if (display === 'SYSML_STATEMACHINE_ZHUANGTAI') {
        // 状态
        const attributeList = await this.getObjectInfo(cellParams)
        const content = attributeList.reduce((prv, item) => {
          if (item.attrLable === '入口操作' && item.attrValueObject) {
            prv += `<div style="text-align: left;padding: 0 10px">entry / ${item.attrValueObject}</div><br/>`
          }
          if (item.attrLable === '出口操作' && item.attrValueObject) {
            prv += `<div style="text-align: left;padding: 0 10px">exit / ${item.attrValueObject}</div><br/>`
          }
          if (item.attrLable === '内部操作' && item.attrValueObject) {
            prv += `<div style="text-align: left;padding: 0 10px">do / ${item.attrValueObject}</div><br/>`
          }
          return prv
        }, '')
        const label = this.getHeader(cell, name, display) + content
        valueObj.setAttribute('label', this.getOutDiv(cell.id, label));
      } else if (display === 'SYSML_BLOCKDEFINITION_WANZHENGPORTJIEDIAN' || display === 'SYSML_INTERNALMODULE_WANZHENGPORTJIEDIAN') {
        valueObj.setAttribute('label', name);
      } else if (display === 'SYSML_BLOCKDEFINITION_DAILIPORTJIEDIAN' || display === 'SYSML_INTERNALMODULE_DAILIPORTJIEDIAN') {
        valueObj.setAttribute('label', name);
      } else if (display === 'SYSML_REQUIREMENT_XQJD') {
        cell.value.setAttribute('name', name)
        // 获取页面当前节点的个数
        let pageObjNum = 0;
        let allCells = myEditor.editor.graph.getDefaultParent() ? myEditor.editor.graph.getDefaultParent().children : null;
        if (allCells != null) {
          pageObjNum = allCells.reduce((prv, item) => {
            if (item.getAttribute("display") == display && item.getAttribute("objectId") != null && item.getAttribute("objectId") == '') {
              prv += 1;
            }
            return prv
          }, 0)
        }
        // 获取数据渲染label
        cellParams.name = name || cellParams.name
        var reqObjectInfoPerParams = {
          pageObjNum: pageObjNum,
          xuqiuId: cell.value.getAttribute('xuqiuId')
        };
        const attributeList = await this.getObjectInfo(cellParams, reqObjectInfoPerParams);
        // 设置ID最大值
        for (var i = 0; i < attributeList.length; i++) {
          if (attributeList[i].attrLable == 'ID' && attributeList[i].attrValueObject != null && attributeList[i].attrValueObject != undefined) {
            attributeList[i].attrValueObject = attributeList[i].attrValueObject;
            valueObj.setAttribute('xuqiuId', attributeList[i].attrValueObject);
          }
        }
        cell.attributeVisibleMap = this.getContentByArray(attributeList, cell.attributeVisibleMap || [])
        this.setRequireEdge(cell)
      } else {
        valueObj.setAttribute('label', label || name);
      }
    } finally {
      const htmlReg = /<[a-z][^>]*?>/i
      if(!cell.style?.includes('html=1') && htmlReg.test(cell.value.getAttribute('label'))) {
        cell.style = 'html=1;' + cell.style;
      }
    }
  }

  /**
   * 格式化图片base64，过滤 [base64;] 字符串
   * @param url {string}
   * @returns {string}
   */
  formatImageDataUrl(url) {
    return Object.prototype.toString.call(url).slice(8, -1) === 'String'
      ? url.replace(/^(data:image\/)(.*)(;base64,)/, function() {
        var args = arguments;
        return args[1] + args[2] + ',';
      })
      : url;
  }

  /**
   * 当前操作不记录到undoManager中
   * @param cb
   */
  ignoreUndo(cb) {
    var undoHistory = window.myEditor.editor.undoManager.history.slice()
    var undoIndex = window.myEditor.editor.undoManager.indexOfNextAdd;
    if (typeof cb === 'function') {
      cb();
    }
    window.myEditor.editor.undoManager.history = undoHistory;
    window.myEditor.editor.undoManager.indexOfNextAdd = undoIndex;
  }

  /**
   * @desc label超出cell，更新cell的尺寸以包裹label
   * @param cell {mxCell}
   */
  updateCellSize(cell, immediate) {
    immediate = immediate == null ? false : immediate;
    var graph = window.myEditor.editor.graph;
    var model = graph.getModel();
    var _this = this;

    if (immediate) {
      resize()
      return;
    }

    model.addListener(mxEvent.CHANGE, handle)

    function resize() {
      var state = graph.view.getState(cell);
      if(!state) return;

      const style = graph.getCellStyle(cell)
      if(style && style[mxConstants.STYLE_VERTICAL_LABEL_POSITION] && style[mxConstants.STYLE_VERTICAL_LABEL_POSITION] !== 'middle') return

      var text = state.text;
      var geo = cell.getGeometry();

      if (!text) return;

      var overW = text.boundingBox.width > geo.width
      var overH = text.boundingBox.height > geo.height
      if (overH || overW) {
        var geo1 = geo.clone()
        if (overH) {
          geo1.height = text.boundingBox.height
        }

        if (overW) {
          geo1.width = text.boundingBox.width
        }

        _this.ignoreUndo(function () {
          model.beginUpdate();
          try {
            model.setGeometry(cell, geo1);
          } finally {
            model.endUpdate();
            graph.refresh(cell)
            graph.view.revalidate();
          }
        })
      }
    }

    function handle(sneder, me) {
      try {
        // 过滤非label更新的change
        var changes = me.getProperty('changes').filter(function (item) {
          return item.cell === cell && (item instanceof mxValueChange || item instanceof mxCellAttributeChange);
        })

        if (changes.length < 1) return;


        resize()

      } finally {
        model.removeListener(handle)
      }
    }
  }

  updateCellSizeImmediate(cell) {
    var valueObj = cell.getValue();
    var display = cell.value.getAttribute('display')

    var excludeFns = [
      function () {
        return cell.style && cell.style.includes('shape=image')
      },
      function () {
        return [
            'SYSML_BLOCKDEFINITION_KUAIJIEDIAN',
            'SYSML_BLOCKDEFINITION_YUESUKUAIJIEDIAN',
            'SYSML_BLOCKDEFINITION_DAILIPORTJIEDIAN',
            'SYSML_INTERNALMODULE_DAILIPORTJIEDIAN',
            'SYSML_ACTIVITY_DIAOYONGDONGZUOJIEDIAN',
            'LABEL_DENGDAISHIJIANDONGZUO',
            'SYSML_ACTIVITY_KONGZHILIULUJING',
            'SYSML_ACTIVITY_DUIXIANGLIUJIEDIAN',
            'SYSML_BLOCKDEFINITION_YUESUKUAIJIEDIAN',
            'UML_COMPONENT_INTERFACE',
            'SYSML_STATEMACHINE_ZHUANGTAI',
            'SYSML_BLOCKDEFINITION_WANZHENGPORTJIEDIAN',
            'SYSML_INTERNALMODULE_WANZHENGPORTJIEDIAN',
            'SYSML_BLOCKDEFINITION_DAILIPORTJIEDIAN',
            'SYSML_INTERNALMODULE_DAILIPORTJIEDIAN',
            'SYSML_REQUIREMENT_XQJD'
          ]
          .concat(window.displayTypeComboStr)
          .includes(display)
      },
      function () {
        return valueObj.getAttribute('tooltip') === '流规范'
      },
      function () {
        return cell.objectLabel || cell.style.includes('swimlane')
      },
      function () {
        return cell.value.nodeName === 'relation'
      }
    ];

    if (excludeFns.some(function (fn) { return fn() }))  {
      return;
    }

    this.updateCellSize(cell, true);
  }

  isEmptyValue(value) {
    return value == null || value === ''
  }
}

function createUtils() {
  return new utils();
}
